package com.wnxy.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

@Component
@Aspect
public class SubmitAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 环绕通知：环绕目标对象方法执行
     * 通过Redis实现接口幂等性保证：相等的方法每次执行后，需要在Redis中保存执行状态。
     * 存入Redis的key：
     * 前缀: submitKey:
     * uri: /user
     * 登录用户的id： 100
     * 最后：
     * submitKey:/user:100
     */
    @Around("@annotation(submitOnTime)")
    public Object around(ProceedingJoinPoint pjp, SubmitOnTime submitOnTime) {

        // 获取request对象
        HttpServletRequest request = ((ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes()).getRequest();
        // 通过request对象获取请求uri
        String uri = request.getRequestURI();
        // 拼接redis的key (用户id从token获取，这里写死为100)
        String redisKey = "submitKey:" + uri + ":100";
        // 判断这个key是否在redis中存在，如果在redis中存在说明是重复操作,不放行； 否则放行
        if (!redisTemplate.hasKey(redisKey)) {
            // 当前操作不是重复操作，redis中不存在记录；
            // 保存执行状态到redis中
            redisTemplate.opsForValue().set(redisKey, redisKey, submitOnTime.expireTime(), TimeUnit.SECONDS);
            try {
                // 放行
                Object proceed = pjp.proceed();
                return proceed;
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        } else {
            // 说明redis中已经有数据.在单位时间内已经操作过该接口
            throw new RuntimeException("请勿重复添加数据");
        }
    }
}
